/*
 * Copyright (c) 2021
 * User:LENOVO
 * File:LRU缓存机制.java
 * Date:2021/02/18 14:22:18
 */

package org.bytedance.数据结构;

import com.alibaba.fastjson.JSON;

import java.util.HashMap;
import java.util.Map;

public class LRU缓存机制 {

    public static void main(String[] args) {
        LRU缓存机制 lRUCache = new LRU缓存机制(2);
        lRUCache.put(1, 1); // 缓存是 {1=1}
        lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
        lRUCache.get(1);    // 返回 1
        lRUCache.put(3, 3); // 该操作会使得关键字 2 作废，缓存是 {1=1, 3=3}
        lRUCache.get(2);    // 返回 -1 (未找到)
        lRUCache.put(4, 4); // 该操作会使得关键字 1 作废，缓存是 {4=4, 3=3}
        lRUCache.get(1);    // 返回 -1 (未找到)
        lRUCache.get(3);    // 返回 3
        lRUCache.get(4);    // 返回 4
    }


    private static class LNode {
        int key;
        int value;
        LNode pre;
        LNode next;

        public LNode() {

        }

        public LNode(int key, int value) {
            this.value = value;
            this.key = key;
        }

        @Override
        public String toString() {
            return "LNode{" +
                    "key=" + key +
                    ", value=" + value +
                    '}';
        }
    }

    private Map<Integer, LNode> cache = new HashMap<>();
    private int size;
    private int capacity;
    private LNode head, tail;


    public LRU缓存机制(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        head = new LNode();
        tail = new LNode();
        head.next = tail;
        tail.pre = head;
    }

    public int get(int key) {
        LNode node = cache.get(key);
        if (node == null) return -1;
        moveToHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        LNode node = cache.get(key);
        if (node == null) {
            LNode lNode = new LNode(key, value);
            cache.put(key, lNode);
            addToHead(lNode);
            ++size;
            if (size > capacity) {
                LNode tail = removeTail();
                cache.remove(tail.key);
                --size;
            }
        } else {
            node.value = value;
            moveToHead(node);
        }
    }

    private void addToHead(LNode node) {
        node.next = head.next;
        head.next.pre = node;
        head.next = node;
        node.pre = head;
    }

    public void moveToHead(LNode node) {
        removeNode(node);
        addToHead(node);
    }

    private LNode removeTail() {
        LNode res = tail.pre;
        removeNode(res);
        return res;
    }

    private void removeNode(LNode node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }
}
